package com.yswy.app.util;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yswy.domain.vo.dto.BaseFilter;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.ToLongFunction;
import java.util.stream.Collector;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.yswy.common.constants.WarnMsgConstants.NAME_REPEAT_MSG;
import static com.yswy.common.constants.WarnMsgConstants.NULL_MSG;

/**
 * @author 19401
 * @date 2022/5/31 11:20
 **/
public class CrudUtils {
    public static <T, E extends BaseFilter> Page<T> page(List<T> list, E filter) {
        Integer pageNum = filter.getPageNum();
        Integer pageSize = filter.getPageSize();
        int total = list.size();

        Page<T> page = new Page<>(pageNum, pageSize, total);
        int pageNumNew = (pageNum - 1) * pageSize;
        list = list.subList(Math.min(pageNumNew, total), Math.min((pageSize + pageNumNew), total));
        page.setRecords(list);
        return page;
    }
    public static <E extends BaseFilter, T> Page<T> page(BaseMapper<T> baseMapper, E filter, Consumer<LambdaQueryWrapper<T>> consumer) {
        LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery();
        consumer.accept(wrapper);
        return baseMapper.selectPage(new Page<>(filter.getPageNum(), filter.getPageSize()), wrapper);
    }
    public static <R, T> Page<R> toPage(Page<T> page, Function<? super T, ? extends R> mapper) {
        return toPage(page, c -> {}, mapper);
    }
    public static <R, T> Page<R> toPage(Page<T> page, Consumer<List<T>> consumer, Function<? super T, ? extends R> mapper) {
        List<T> records = page.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return new Page<>();
        }
        consumer.accept(records);
        Page<R> validPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        validPage.setRecords(records.stream().map(mapper).collect(Collectors.toList()));
        return validPage;
    }
    public static <R, T, F extends BaseFilter> Page<R> page(BaseMapper<T> baseMapper, F filter,
                                                            Consumer<LambdaQueryWrapper<T>> selectWrapper,
                                                            Consumer<List<T>> result,
                                                            Function<? super T, ? extends R> mapper) {
        LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery();
        selectWrapper.accept(wrapper);
        Page<T> page = baseMapper.selectPage(new Page<>(filter.getPageNum(), filter.getPageSize()), wrapper);
        return toPage(page, result, mapper);
    }

    public static <T> List<T> tree(List<T> list,
                                   Consumer<? super T> action,
                                   Predicate<? super T> predicate) {
        return treeSorted(list, action, predicate, null);
    }
    public static <T> List<T> treeSorted(List<T> list,
                                         Consumer<? super T> action,
                                         Predicate<? super T> predicate,
                                         Comparator<? super T> sorted) {
        list = null == sorted ? stream(list).collect(Collectors.toList()) : sorted(list, sorted);
        list.forEach(action);
        list = filter(list, predicate);
        return list;
    }
    public static <T> Integer selectCount(BaseMapper<T> baseMapper, Consumer<LambdaQueryWrapper<T>> consumer) {
        LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery();
        consumer.accept(wrapper);
        return baseMapper.selectCount(wrapper);
    }

    public static <T> T selectById(BaseMapper<T> baseMapper, Serializable id) {
        T bo = baseMapper.selectById(id);
        Assert.state(null != bo, NULL_MSG);
        return bo;
    }

    public static <T> T selectOne(BaseMapper<T> baseMapper, Consumer<LambdaQueryWrapper<T>> consumer) {
        return selectOne(baseMapper, consumer, true);
    }
    public static <T> T selectOne(BaseMapper<T> baseMapper, Consumer<LambdaQueryWrapper<T>> consumer, boolean isVerify) {
        LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery();
        consumer.accept(wrapper);
        T bo = baseMapper.selectOne(wrapper);
        if (!isVerify) {
            return bo;
        }
        Assert.state(null != bo, NULL_MSG);
        return bo;
    }

    public static <T> List<T> selectList(BaseMapper<T> baseMapper, Consumer<LambdaQueryWrapper<T>> consumer) {
        LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery();
        consumer.accept(wrapper);
        return baseMapper.selectList(wrapper);
    }
    public static <T, R> List<R> list(BaseMapper<T> baseMapper, Consumer<LambdaQueryWrapper<T>> consumer, Function<? super T, ? extends R> mapper) {
        return list(baseMapper, consumer, f -> true, mapper);
    }
    public static <T, R> List<R> list(BaseMapper<T> baseMapper, Consumer<LambdaQueryWrapper<T>> consumer, Predicate<? super T> predicate, Function<? super T, ? extends R> mapper) {
        LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery();
        consumer.accept(wrapper);
        List<T> list = baseMapper.selectList(wrapper);
        return filterAndMap(list, predicate, mapper);
    }

//    public static <T> void create(BaseMapper<T> baseMapper,
//                                  Consumer<LambdaQueryWrapper<T>> verifyConsumer,
//                                  Consumer<T> insertConsumer) {
//        if (null != verifyConsumer) {
//            verifyName(baseMapper, verifyConsumer);
//        }
//        T t = null;
//        insertConsumer.accept(t);
//        int insert = baseMapper.insert(t);
//        Assert.isTrue(insert > 0, "添加失败");
//    }
    public static <T> void verifyRepeat(BaseMapper<T> baseMapper, Consumer<LambdaQueryWrapper<T>> consumer, String verifyInfoConsumer) {
        LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery();
        consumer.accept(wrapper);
        Integer count = baseMapper.selectCount(wrapper);
        Assert.state(0 == count, StringUtils.isNotEmpty(verifyInfoConsumer) ? verifyInfoConsumer : NAME_REPEAT_MSG);
    }

    public static <T> void updateBatch(BaseMapper<T> baseMapper, List<T> updates, Consumer<T> consumer) {
        for (T update : updates) {
            consumer.accept(update);
            baseMapper.updateById(update);
        }
    }
    public static <T> void createOrUpdate(BaseMapper<T> baseMapper, Long id, T t) {
        createOrUpdate(baseMapper, id, t, null, null);
    }
    public static <T> void createOrUpdate(BaseMapper<T> baseMapper, Long id, T t, Consumer<LambdaQueryWrapper<T>> verifyConsumer) {
        createOrUpdate(baseMapper, id, t, verifyConsumer, null);
    }
    public static <T> void createOrUpdate(BaseMapper<T> baseMapper, Long id, T t, Consumer<LambdaQueryWrapper<T>> verifyConsumer, String verifyInfoConsumer) {
        if (null != verifyConsumer) {
            verifyRepeat(baseMapper, verifyConsumer, verifyInfoConsumer);
        }
        int i = null == id ? baseMapper.insert(t) : baseMapper.updateById(t);
        Assert.isTrue(i > 0, (null == id ? "添加" : "更新") + "失败");
    }
    public static <T> void delete(BaseMapper<T> baseMapper, Consumer<LambdaQueryWrapper<T>> consumer) {
        LambdaQueryWrapper<T> wrapper = Wrappers.lambdaQuery();
        consumer.accept(wrapper);
        int delete = baseMapper.delete(wrapper);
        Assert.isTrue(delete >= 0, "删除失败");
    }
    public static <T> void delete(BaseMapper<T> baseMapper, Long id) {
        int delete = baseMapper.deleteById(id);
        Assert.isTrue(delete > 0, "删除失败");
    }

    // =================================================================================================================
    public static <T> Map<Object, List<T>> group(List<T> list, Function<? super T, ? extends Object> classifier) {
        return stream(list).collect(Collectors.groupingBy(classifier));
    }
    public static <T> Map<Object, List<T>> groupSorted(List<T> list, Function<? super T, ? extends Object> classifier,
                                                     Comparator<? super T> sorted) {
        Stream<? extends T> stream = stream(list);
        return null == sorted ? stream.collect(Collectors.groupingBy(classifier)) :
                stream.sorted(sorted).collect(Collectors.groupingBy(classifier));
    }
    public static <T> Long count(List<T> list, Predicate<? super T> predicate) {
        return stream(list).filter(predicate).count();
    }
    public static <T, A, R> R sortedCollect(List<T> list, Comparator<? super T> comparator, Collector<? super T, A, R> collectors) {
        return stream(list).sorted(comparator).collect(collectors);
    }
    public static <T> List<T> sorted(List<T> list, Comparator<? super T> comparator) {
        return stream(list).sorted(comparator).collect(Collectors.toList());
    }
    public static <T> List<T> filter(List<T> list, Predicate<? super T> predicate) {
        return filterAndMap(list, predicate, m -> m);
    }
    public static <T> List<T> filter(List<T> list, Predicate<? super T> predicate, Boolean isDistinct) {
        return filterAndMap(list, predicate, m -> m, isDistinct);
    }
    public static <T> List<T> peek(List<T> list, Consumer<? super T> action) {
        return stream(list).peek(action).collect(Collectors.toList());
    }
    public static <T, R> List<R> map(List<T> list, Function<? super T, ? extends R> mapper) {
        return filterAndMap(list, f -> true, mapper);
    }
    public static <T, R> List<R> map(List<T> list, Function<? super T, ? extends R> mapper, Boolean isDistinct) {
        return filterAndMap(list, f -> true, mapper, isDistinct);
    }
    public static <T, R> List<R> filterAndMap(List<T> list, Predicate<? super T> predicate, Function<? super T, ? extends R> mapper) {
        return filterAndMap(list, predicate, mapper, false);
    }
    public static <T, R> List<R> filterAndMap(List<T> list, Predicate<? super T> predicate, Function<? super T, ? extends R> mapper, Boolean isDistinct) {
        Stream<? extends R> stream = stream(list).filter(predicate).map(mapper);
        if (isDistinct) {
            stream = stream.distinct();
        }
        return stream.collect(Collectors.toList());
    }

    public static <T, A, R> R filterCollect(List<T> list, Predicate<? super T> predicate, Collector<? super T, A, R> collector) {
        return stream(list).filter(predicate).collect(collector);
    }
    public static <T> List<T> distinct(List<T> list) {
        return filterAndMap(list, f -> true, m -> m, true);
    }

    public static <T> Long sum(List<T> list, ToLongFunction<? super T> mapper) {
        return stream(list).mapToLong(mapper).sum();
    }

    public static <T> Long sum(List<T> list, Predicate<? super T> predicate, ToLongFunction<? super T> mapper) {
        return stream(list).filter(predicate).mapToLong(mapper).sum();
    }

    public static <T> List<T> isEmpty(List<T> list) {
        return null == list ? Collections.emptyList() : list;
    }

    public static <R, A, T> R collect(List<T> list, Collector<? super T, A, R> collector) {
        return stream(list).collect(collector);
    }
    public static <T> Stream<? extends T> stream(List<T> list) {
        return isEmpty(list).stream();
    }
}
